此系列文章是以我的業餘專案: Kimoji 作為範例。
這款以純 Jetpack Compose 撰寫的 side project,已經在 Google Play 上架。 歡迎試玩!
立馬下載 限免兌換碼
在 Compose 當中,我們是不用隱藏 UI 元件的。只要我們不把這些元件加到 composition 裡就好,然後這些元件就不會加入 Compose 產生的 UI 樹狀結構了。只要使用簡單的 Kotlin 條件式邏輯就能達到這個效果。舉例來說,如果想顯示 onboarding 畫面,或日記本,我們可以這樣做:
@Composable
fun KimojiApp() {
if (shouldShowOnboarding) { // Where does this come from?
OnboardingScreen()
} else {
Journal()
}
}
但是,我們無法存取 shouldShowOnboarding
。顯然我們需要和 KimojiApp
composable 分享我們在 OnboardingScreen
建立的狀態。
我們不用想辦法把值分享給 parent,只要「hoist」就好,直接把值移動到需要存取的 common ancestor 裡面。
像是這樣:
@Composable
fun KimojiApp() {
var shouldShowOnboarding by remember { mutableStateOf(true) }
if (shouldShowOnboarding) {
OnboardingScreen(/* TODO */)
} else {
Journal()
}
}
我們還需要和 onboarding 畫面分享 shouldShowOnboarding
,但是不必直接進行傳遞。我們可以不讓 OnboardingScreen
變更狀態,而是讓它通知我們使用者已經按下「Hi, Kimoji!」 按鈕,這樣的處理方式比較好。
如何向上傳遞事件呢?答案是向下傳遞 callbacks。Callbacks 是傳遞給其他函式當做參數的函式,在觸發事件時,就會執行這個函式。
我們來試著為 onboarding 畫面新增函式參數,定義為 onHiClicked: () -> Unit
,以便變更 KimojiApp
裡的狀態。
解法:
@Composable
fun KimojiApp() {
var shouldShowOnboarding by remember { mutableStateOf(true) }
if (shouldShowOnboarding) {
OnboardingScreen(onHiClicked = { shouldShowOnboarding = false })
} else {
Journal()
}
}
@Composable
fun OnboardingScreen(onHiClicked: () -> Unit) {
Surface {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(R.drawable.joy),
contentDescription = null,
modifier = Modifier
.padding(vertical = 24.dp)
.size(40.dp)
.clip(CircleShape)
)
Text("Welcome to the Kimoji!")
Button(
modifier = Modifier.padding(vertical = 24.dp),
onClick = onHiClicked
) {
Text("Hi, Kimoji!")
}
}
}
}
藉由傳遞函式 (而不是 state) 給 OnboardingScreen
,這個 composable 可以更容易被複用,也能保護 state 不會因為其他 composable 而變動。大致上來說,這個方法可以讓一切都簡潔許多。我們可以來看看現在如何修改 onboarding 的 preview 畫面來呼叫 OnboardingScreen
:
@Preview(showBackground = true, widthDp = 320, heightDp = 320)
@Composable
fun OnboardingPreview() {
KimojiTheme {
OnboardingScreen(onHiClicked = {}) // Do nothing on click.
}
}
把 onHiClicked
指派給空白的 lambda 代表「什麼都不做」,這十分適合給預覽畫面使用。
此系列文章是以我的業餘專案:Kimoji 為範例。
Kimoji 是一款心情日記 App,讓你用可愛的 emoji 來撰寫你的心情日記。現在就來試試這款設計精美的微日記吧!
立馬下載 限免兌換碼
Reference: https://developer.android.com/codelabs/jetpack-compose-basics